package com.example.securitydemo.security.jwt;


import com.example.securitydemo.config.AppProperties;
import com.example.securitydemo.util.CollectionUtil;
import com.example.securitydemo.util.JwtUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
import lombok.val;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Component
public class JwtFilter extends OncePerRequestFilter {

    private final AppProperties appProperties;

    public JwtFilter(AppProperties appProperties) {
        this.appProperties = appProperties;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        if (checkJwtToken(httpServletRequest)) {
            validateToken(httpServletRequest)
                    .filter(claims -> claims.get("authorities") != null)
                    .ifPresentOrElse(
                            this::setupSpringAuthentication, // 有值
                            SecurityContextHolder::clearContext // 为空
                    );
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    private void setupSpringAuthentication(Claims claims) {
        val rawList = CollectionUtil.convertObjectToList(claims.get("authorities"));
        // 遍历将权限改为String
        val authorities = rawList.stream()
                .map(String::valueOf)
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        // 设置 token
        val authentication =
                new UsernamePasswordAuthenticationToken(claims.getSubject(), null, authorities);
        // 设置 权限
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    private Optional<Claims> validateToken(HttpServletRequest request) {
        String token = request.getHeader(appProperties.getJwt().getHeader())
                .replace(appProperties.getJwt().getPrefix(), "");
        try {
            return Optional.of(Jwts.parserBuilder()
                    .setSigningKey(JwtUtil.accessTokenKey)
                    .build()
                    .parseClaimsJws(token)
                    .getBody());
        } catch (ExpiredJwtException | SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException e) {
            return Optional.empty();
        }
    }

    private boolean checkJwtToken(HttpServletRequest request) {
        String jwt = request.getHeader(appProperties.getJwt().getHeader());
        return jwt != null && jwt.startsWith(appProperties.getJwt().getPrefix());
    }
}
